package com.yfqy.app.modules.order.adapter;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.yfqy.app.concurrency.StockService;
import com.yfqy.app.configure.Idgenerator.SnowflakeIdGenerator;
import com.yfqy.app.constant.GeneralConstants;
import com.yfqy.app.constant.OrderConstants;
import com.yfqy.app.constant.RedisKeyConstants;
import com.yfqy.app.constant.SystemConfigConstants;
import com.yfqy.app.domain.entity.Customer;
import com.yfqy.app.domain.entity.CustomerAddress;
import com.yfqy.app.domain.entity.IntegralRecord;
import com.yfqy.app.domain.entity.OrderAddress;
import com.yfqy.app.domain.entity.OrderInfo;
import com.yfqy.app.domain.entity.OrderItem;
import com.yfqy.app.domain.entity.ProductSku;
import com.yfqy.app.domain.entity.ProductSpu;
import com.yfqy.app.domain.entity.Promotion;
import com.yfqy.app.domain.entity.PromotionProduct;
import com.yfqy.app.domain.entity.PromotionRule;
import com.yfqy.app.domain.entity.ScheduledTask;
import com.yfqy.app.domain.mapper.CustomerAddressMapper;
import com.yfqy.app.domain.mapper.CustomerMapper;
import com.yfqy.app.domain.mapper.IntegralRecordMapper;
import com.yfqy.app.domain.mapper.OrderAddressMapper;
import com.yfqy.app.domain.mapper.OrderInfoMapper;
import com.yfqy.app.domain.mapper.OrderItemMapper;
import com.yfqy.app.domain.mapper.ProductSkuMapper;
import com.yfqy.app.domain.mapper.ProductSpuMapper;
import com.yfqy.app.domain.mapper.PromotionMapper;
import com.yfqy.app.domain.mapper.PromotionProductMapper;
import com.yfqy.app.domain.mapper.ScheduledTaskMapper;
import com.yfqy.app.enums.AreaStatus;
import com.yfqy.app.enums.ErrorCode;
import com.yfqy.app.enums.IntegralType;
import com.yfqy.app.enums.OrderType;
import com.yfqy.app.enums.ProductStatus;
import com.yfqy.app.enums.SysUserStatus;
import com.yfqy.app.enums.TaskType;
import com.yfqy.app.exception.BusinessException;
import com.yfqy.app.modules.order.builder.OrderCreateBuilder;
import com.yfqy.app.modules.order.context.OrderBuilderContext;
import com.yfqy.app.modules.order.dto.LockedStockDTO;
import com.yfqy.app.modules.order.dto.OrderAmountDTO;
import com.yfqy.app.modules.order.dto.OrderCreateRequest;
import com.yfqy.app.modules.order.dto.OrderInfoDTO;
import com.yfqy.app.modules.order.dto.OrderItemRequest;
import com.yfqy.app.modules.order.dto.PointsDeductionDTO;
import com.yfqy.app.modules.system.dto.DeductionDTO;
import com.yfqy.app.modules.system.dto.ShippingFreeDTO;
import com.yfqy.app.modules.system.service.SystemConfigService;
import com.yfqy.app.util.AuthUserContext;
import com.yfqy.app.util.JSON;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
public abstract class OrderCreateBuilderAdapter implements OrderCreateBuilder {

    private static final Logger logger = LoggerFactory.getLogger(OrderCreateBuilderAdapter.class);

    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private CustomerAddressMapper customerAddressMapper;
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private ProductSpuMapper productSpuMapper;
    @Autowired
    private ProductSkuMapper productSkuMapper;
    @Autowired
    private ScheduledTaskMapper scheduledTaskMapper;
    @Autowired
    private SnowflakeIdGenerator idGenerator;
    @Autowired
    private IntegralRecordMapper integralRecordMapper;
    @Autowired
    private StockService stockService;
    @Autowired
    private PromotionProductMapper promotionProductMapper;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private OrderAddressMapper orderAddressMapper;
    @Autowired
    private PromotionMapper promotionMapper;
    @Autowired
    @Qualifier("defaultThreadPoolExecutor")
    private ThreadPoolExecutor threadPoolExecutor;


    @Override
    public void validateParams(OrderCreateRequest request) {
        // 1. 用户信息校验
        validateCustomer(request);

        // 2. 订单地址参数校验
        validateOrderAddress(request);

        // 3. 积分使用校验
        validateIntegralUsage(request);

        // 4. 运费配置校验
        validateShippingConfig();

        // 5. 订单类型校验
        validateOrderType(request);

        logger.debug("订单参数验证通过: userId={}", request.getUserId());
    }

    @Override
    public void validatePrice(OrderItemRequest item, Map<Long, ProductSpu> spuMap, PromotionProduct promotionProduct) {
        if (promotionProduct.getPromotionPrice().compareTo(item.getUnitPrice()) != 0) {
            String spuName = spuMap.get(item.getSpuId()).getSpuName();
            String errorMsg = String.format("商品[%s]价格不匹配，促销价:%s，提交价:%s",
                    spuName, promotionProduct.getPromotionPrice(), item.getUnitPrice());
            throw new BusinessException(ErrorCode.PRODUCT_PRICE_ERROR.getCode(), errorMsg);
        }
    }

    /**
     * 校验price
     */
    @Override
    public void validatePrice(List<OrderItemRequest> items, Map<Long, ProductSpu> spuMap, Map<Long, ProductSku> skuMap) {
        List<String> priceAnomalyProducts = items.stream()
                .filter(item -> {
                    ProductSku sku = skuMap.get(item.getSkuId());
                    return sku.getPrice().compareTo(item.getUnitPrice()) != 0;
                })
                .map(item -> spuMap.get(item.getSpuId()).getSpuName())
                .toList();

        if (CollUtil.isNotEmpty(priceAnomalyProducts)) {
            throw new BusinessException(ErrorCode.PRODUCT_PRICE_ERROR.getCode(),
                    JSON.stringify(priceAnomalyProducts) + ErrorCode.PRODUCT_PRICE_ERROR.getMessage());
        }
    }

    /**
     * 批量获取并验证SPU
     */
    @Override
    public Map<Long, ProductSpu> batchGetAndValidateSpus(List<Long> spuIds) {
        List<ProductSpu> productSpus = productSpuMapper.selectSpuNameBySpuIds(spuIds);
        // 非法的spu
        if (productSpus.size() != spuIds.size()) {
            List<Long> notFoundIds = spuIds.stream()
                    .filter(id -> productSpus.stream().noneMatch(spu -> spu.getId().equals(id)))
                    .toList();
            throw new BusinessException(ErrorCode.PRODUCT_NOT_EXIST.getCode(), "以下SPU不存在: " + notFoundIds);
        }

        // 过滤已下架商品
        List<String> offlineSpus = productSpus.stream()
                .filter(spu -> spu.getStatus() != ProductStatus.AVAILABLE.getState())
                .map(ProductSpu::getSpuName)
                .toList();

        if (CollUtil.isNotEmpty(offlineSpus)) {
            throw new BusinessException(ErrorCode.PRODUCT_NOT_EXIST.getCode(),
                    JSON.stringify(offlineSpus) + ErrorCode.PRODUCT_NOT_EXIST.getMessage());
        }

        return productSpus.stream()
                .collect(Collectors.toMap(ProductSpu::getId, Function.identity()));
    }

    /**
     * 批量获取并验证SKU
     */
    @Override
    public Map<Long, ProductSku> batchGetAndValidateSkus(List<Long> skuIds, Map<Long, ProductSpu> spuMap) {
        List<ProductSku> skus = productSkuMapper.selectSkusByIds(skuIds);
        if (skus.size() != skuIds.size()) {
            throw new BusinessException(ErrorCode.SKU_NOT_EXIST);
        }

        // 验证SKU与SPU的关联关系
        skus.forEach(sku -> {
            if (!spuMap.containsKey(sku.getSpuId())) {
                throw new BusinessException(ErrorCode.SKU_SPU_MISMATCH);
            }
        });

        return skus.stream()
                .collect(Collectors.toMap(ProductSku::getId, Function.identity()));
    }

    @Override
    public PromotionProduct getAndValidatePromotion(Long promotionId, Long skuId) {
        if (promotionId == null) {
            throw new BusinessException(ErrorCode.PROMOTION_NOT_FOUND);
        }

        Promotion promotion = promotionMapper.selectByPrimaryKey(promotionId);
        if (promotion == null) {
            throw new BusinessException(ErrorCode.PROMOTION_NOT_FOUND);
        }

        // 检查促销活动时间有效性
        if (promotion.getStartTime().after(new Date())
                || promotion.getEndTime().before(new Date())
                || promotion.getStatus() != 1) {
            throw new BusinessException(ErrorCode.PROMOTION_NOT_FOUND);
        }

        // 根据活动Id和skuId查询活动中的sku商品信息
        PromotionProduct promotionProduct = promotionProductMapper.selectByPromotionIdAndSkuId(promotionId, skuId);
        if (promotionProduct == null) {
            throw new BusinessException(ErrorCode.PROMOTION_PRODUCT_NOT_FOUND);
        }

        return promotionProduct;
    }

    @Override
    public void validateStock(OrderItemRequest item, Map<Long, ProductSpu> spuMap, PromotionProduct promotionProduct) {
        if (item.getQuantity() > promotionProduct.getPromotionStock()) {
            String spuName = spuMap.get(item.getSpuId()).getSpuName();
            String errorMsg = String.format("商品[%s]库存不足，剩余:%s，需要:%s",
                    spuName, promotionProduct.getPromotionStock(), item.getQuantity());
            throw new BusinessException(ErrorCode.PRODUCT_STOCK_INSUFFICIENT.getCode(), errorMsg);
        }
    }

    /**
     * 校验库存
     */
    @Override
    public void validateStock(List<OrderItemRequest> items,
                              Map<Long, ProductSpu> spuMap,
                              Map<Long, ProductSku> skuMap) {
        List<String> outOfStockProducts = items.stream()
                .filter(item -> {
                    ProductSku sku = skuMap.get(item.getSkuId());
                    return sku.getStock() < item.getQuantity();
                })
                .map(item -> spuMap.get(item.getSpuId()).getSpuName())
                .toList();

        if (CollUtil.isNotEmpty(outOfStockProducts)) {
            throw new BusinessException(ErrorCode.PRODUCT_STOCK_INSUFFICIENT.getCode(),
                    JSON.stringify(outOfStockProducts) + ErrorCode.PRODUCT_STOCK_INSUFFICIENT.getMessage());
        }
    }

    @Override
    public void validatePurchaseLimit(OrderItemRequest item, Long customerId, PromotionProduct promotionProduct) {
        if (promotionProduct.getPurchaseLimit() <= 0) {
            return;
        }

        int alreadyPurchased = orderItemMapper.selectCountByPromotionId(
                customerId, promotionProduct.getPromotionId(), promotionProduct.getSkuId()
        );

        if (item.getQuantity() + alreadyPurchased > promotionProduct.getPurchaseLimit()) {
            throw new BusinessException(ErrorCode.PURCHASE_LIMIT_EXCEEDED.getCode(),
                    "每人限购" + promotionProduct.getPurchaseLimit());
        }
    }

    /**
     * 填充Sku信息
     */
    @Override
    public void completeSku(OrderItemRequest item, Map<Long, ProductSpu> spuMap, ProductSku productSku) {
        item.setSkuSpecs(productSku.getSpecs());
        item.setSkuImage(productSku.getImage());
        item.setSpuName(spuMap.get(item.getSpuId()).getSpuName());

    }

    @Override
    public void completeSku(List<OrderItemRequest> items, Map<Long, ProductSpu> spuMap, Map<Long, ProductSku> skuMap) {
        items.forEach(item -> {
            item.setSkuSpecs(skuMap.get(item.getSkuId()).getSpecs());
            item.setSkuImage(skuMap.get(item.getSkuId()).getImage());
            item.setSpuName(spuMap.get(item.getSpuId()).getSpuName());
        });
    }


    @Override
    public LockedStockDTO lockStock(OrderCreateRequest request) {
        // 锁定库存
        String prefix = RedisKeyConstants.PRODUCT_STOCK;
        if (request.getPromotionId() != null) {
            prefix = RedisKeyConstants.PRODUCT_PROMOTION_STOCK;
        }
        // 2. 准备锁定数据
        Map<Long, Integer> skuNumbers = request.getItems().stream()
                .collect(Collectors.toMap(
                        item -> item.getPromotionProductId() != null ?
                                item.getPromotionProductId() : item.getSkuId(),
                        OrderItemRequest::getQuantity,
                        Integer::sum)); // 合并相同SKU的数量

        // 3. 分布式锁+Redis库存预扣减
        boolean redisLockSuccess = false;
        // 先使用redis的单线程特性，保证不会超卖
        redisLockSuccess = stockService.deductMultiStockWithRetry(
                skuNumbers, prefix,
                3, // 重试次数
                100 // 重试间隔ms
        );

        if (!redisLockSuccess) {
            throw new BusinessException(ErrorCode.STOCK_NOT_ENOUGH);
        }

        // 4. MySQL库存实际扣减
        int affectedRows;
        if (request.getPromotionId() == null) {
            affectedRows = productSkuMapper.deductMultiStock(skuNumbers);
        } else {
            affectedRows = promotionProductMapper.deductMultiStock(request.getPromotionId(), skuNumbers);
        }
        if (affectedRows != skuNumbers.size()) {
            logger.warn("变更行数affectedRows={}，需要变更的行数={}", affectedRows, skuNumbers.size());
            stockService.rollBackedMultiStock(skuNumbers, prefix);
            throw new BusinessException(ErrorCode.STOCK_DEDUCT_FAILED);
        }
        return new LockedStockDTO(skuNumbers, prefix);
    }

    @Override
    public void saveOrder(OrderInfoDTO orderInfoDTO) {
        // 保存订单主表
        OrderInfo orderInfo = BeanUtil.toBean(orderInfoDTO, OrderInfo.class);
        orderInfoMapper.insert(orderInfo);

        // 保存订单商品表
        List<OrderItem> orderItems = BeanUtil.copyToList(orderInfoDTO.getOrderItems(), OrderItem.class);
        orderItemMapper.batchInsert(orderItems);

        // 保存订单地址表
        OrderAddress orderAddress = BeanUtil.toBean(orderInfoDTO.getOrderAddressDTO(), OrderAddress.class);
        orderAddressMapper.insert(orderAddress);
    }

    // 提交异步任务
    @Override
    public void afterOrderCreated(int points, long userId, Long orderId, Date payExpireTime) {
        // 任务1：订单超时任务
        threadPoolExecutor.execute(() -> {
            addTimeoutTask(orderId, payExpireTime);
        });
        // 任务2：扣除用户积分&&添加用户积分变更记录
        if (points > 0) {
            threadPoolExecutor.execute(() -> {
                deductUserPointsAndAddIntegralRecord(points, userId, orderId);
            });
        }
    }

    @Override
    public DeductionDTO getPointsDeductionConfig() {
        Object object = OrderBuilderContext.getValue(OrderConstants.INTEGRAL_DEDUCTION_RULE);
        if (object instanceof DeductionDTO) {
            return (DeductionDTO) object;
        }
        return null;
    }

    /**
     * 获取满减规则（从上下文）
     */
    @Override
    public PromotionRule getFullDiscountRule() {
        Object ruleObj = OrderBuilderContext.getValue(OrderConstants.FULL_DISCOUNT_CONF);
        if (ruleObj instanceof PromotionRule) {
            return (PromotionRule) ruleObj;
        }
        return null;
    }

    @Override
    public PromotionRule getGroupRule() {
        Object ruleObj = OrderBuilderContext.getValue(OrderConstants.GROUP_ORDER_CONF);
        if (ruleObj instanceof PromotionRule) {
            return (PromotionRule) ruleObj;
        }
        return null;
    }

    @Override
    public PromotionRule getDiscountRule() {
        Object ruleObj = OrderBuilderContext.getValue(OrderConstants.DISCOUNT_CONF);
        if (ruleObj instanceof PromotionRule) {
            return (PromotionRule) ruleObj;
        }
        return null;
    }

    @Override
    public boolean isPointsDeductionEnabled(DeductionDTO deductionDTO) {
        return deductionDTO.getRatio().compareTo(BigDecimal.ZERO) > 0
                && deductionDTO.getPoints_per_yuan() > 0;
    }

    /**
     * 应用积分抵扣逻辑
     *
     * @param amountDTO     订单金额DTO（会被修改）
     * @param paymentAmount 可抵扣的金额基数（通常是优惠后的金额）
     */
    @Override
    public void applyPointsDeduction(OrderAmountDTO amountDTO, BigDecimal paymentAmount) {
        // 1. 初始化默认值
        resetPointsDeduction(amountDTO);

        // 2. 检查积分抵扣是否可用
        DeductionDTO config = getPointsDeductionConfig();
        if (config == null || !isPointsDeductionEnabled(config)) {
            return;
        }

        // 3. 获取当前用户
        Customer customer = getCurrentCustomer();
        if (customer.getPoints() <= 0) {
            return;
        }

        // 4. 计算抵扣金额和所需积分
        PointsDeductionDTO deduction = calculateOptimalDeduction(
                paymentAmount,
                customer.getPoints(),
                config
        );

        // 5. 应用计算结果
        applyDeductionToAmount(amountDTO, deduction);
    }

    /**
     * 重置积分抵扣字段
     */
    protected void resetPointsDeduction(OrderAmountDTO amountDTO) {
        amountDTO.setPoints(0);
        amountDTO.setPointAmount(BigDecimal.ZERO);
    }

    @Override
    public Customer getCurrentCustomer() {
        Object object = OrderBuilderContext.getValue(OrderConstants.CREATE_ORDER_USER_INFO);
        if (object instanceof Customer) {
            return (Customer) object;
        }
        logger.warn("用户解析失败");
        throw new BusinessException(ErrorCode.USER_NOT_EXIST);
    }

    @Override
    public PointsDeductionDTO calculateOptimalDeduction(BigDecimal paymentAmount,
                                                        int availablePoints,
                                                        DeductionDTO config) {
        // 计算最大可抵扣金额
        BigDecimal maxDeduction = paymentAmount.multiply(config.getRatio())
                .setScale(2, RoundingMode.HALF_UP);

        // 计算所需积分
        int pointsNeeded = calculatePointsNeeded(maxDeduction, config);

        // 根据用户积分决定实际抵扣方案
        if (availablePoints >= pointsNeeded) {
            return new PointsDeductionDTO(pointsNeeded, maxDeduction);
        } else {
            BigDecimal actualAmount = calculatePointsAmount(availablePoints, config);
            return new PointsDeductionDTO(availablePoints, actualAmount);
        }
    }

    /**
     * 根据积分计算规则config，计算amount需要多少积分
     *
     * @param amount
     * @param config
     * @return
     */
    protected int calculatePointsNeeded(BigDecimal amount, DeductionDTO config) {
        return amount.multiply(new BigDecimal(config.getPoints_per_yuan()))
                .setScale(0, RoundingMode.HALF_UP)
                .intValue();
    }

    /**
     * 根据积分计算规则config，计算points可以抵扣多少金额
     *
     * @param points
     * @param config
     * @return
     */
    protected BigDecimal calculatePointsAmount(int points, DeductionDTO config) {
        return new BigDecimal(points).divide(new BigDecimal(config.getPoints_per_yuan()), 2, RoundingMode.HALF_UP);
    }

    @Override
    public void applyDeductionToAmount(OrderAmountDTO amountDTO, PointsDeductionDTO deduction) {
        amountDTO.setPoints(deduction.getPoints());
        amountDTO.setPointAmount(deduction.getAmount());
    }

    @Override
    public void calculateFreightAmount(OrderAmountDTO amountDTO) {
        // 运费初始值
        amountDTO.setFreightAmount(BigDecimal.ZERO);

        // 根据运费满减规则设置
        Object object = OrderBuilderContext.getValue(OrderConstants.SHIPPING_FEE);
        if (object instanceof ShippingFreeDTO freeConfig) {
            if (amountDTO.getPaymentAmount().compareTo(freeConfig.getFree_threshold()) < 0) {
                amountDTO.setFreightAmount(freeConfig.getDefault_fee());
            }
        }

        // 订单总价需要加上运费
        amountDTO.setTotalAmount(amountDTO.getTotalAmount().add(amountDTO.getFreightAmount()));
        amountDTO.setPaymentAmount(amountDTO.getPaymentAmount().add(amountDTO.getFreightAmount()));
    }

    private void validateCustomer(OrderCreateRequest request) {
        Long customerId = AuthUserContext.getUserId();
        if (customerId == null) {
            logger.warn("用户未登录");
            throw new BusinessException(ErrorCode.USER_NOT_LOGIN);
        }

        Customer customer = customerMapper.selectByPrimaryKey(customerId);
        if (customer == null) {
            logger.warn("用户不存在: userId={}", customerId);
            throw new BusinessException(ErrorCode.USER_NOT_EXIST);
        }

        // 检查用户状态
        if (!SysUserStatus.VALID.getCode().equals(customer.getStatus())) {
            logger.warn("用户状态异常: userId={}, status={}", customerId, customer.getStatus());
            throw new BusinessException(ErrorCode.USER_STATUS_ERROR);
        }

        request.setUserId(customerId);
        OrderBuilderContext.setValue(OrderConstants.CREATE_ORDER_USER_INFO, customer);

    }

    /**
     * 订单地址参数校验
     */
    private void validateOrderAddress(OrderCreateRequest request) {

        CustomerAddress customerAddress = customerAddressMapper.selectByPrimaryKey(request.getAddressId());
        // 验证地址信息
        if (customerAddress == null
                || customerAddress.getStatus() != AreaStatus.OPENED.getStatus()
                || !request.getUserId().equals(customerAddress.getCustomerId())) {
            throw new BusinessException(ErrorCode.ORDER_ADDRESS_ERROR);
        }

        OrderBuilderContext.setValue(OrderConstants.ORDER_ADDRESS, customerAddress);
    }

    /**
     * 积分使用校验
     */
    private void validateIntegralUsage(OrderCreateRequest request) {
        if (!request.isUsePoints()) {
            return;
        }

        logger.info("用户使用积分抵扣: userId={}", request.getUserId());

        String deductionRule = systemConfigService.getConfigValue(
                SystemConfigConstants.CONFIG_GROUP_INTEGRAL,
                SystemConfigConstants.CONFIG_KEY_DEDUCTION_RULE
        );

        if (StringUtils.isNotBlank(deductionRule)) {
            OrderBuilderContext.setValue(OrderConstants.INTEGRAL_DEDUCTION_RULE, JSON.parse(deductionRule, DeductionDTO.class));
        } else {
            logger.warn("积分抵扣规则未配置");
            // 根据业务决定：是抛出异常还是继续执行
            throw new BusinessException(ErrorCode.INTEGRAL_RULE_NOT_CONFIGURED);
        }
    }

    /**
     * 运费配置校验
     */
    private void validateShippingConfig() {
        String shippingFee = systemConfigService.getConfigValue(
                SystemConfigConstants.CONFIG_GROUP_ORDER,
                SystemConfigConstants.CONFIG_KEY_SHIPPING_FEE
        );

        if (StringUtils.isNotBlank(shippingFee)) {
            OrderBuilderContext.setValue(OrderConstants.SHIPPING_FEE, JSON.parse(shippingFee, ShippingFreeDTO.class));
        } else {
            logger.info("运费配置未设置，使用默认值");
            //OrderBuilderContext.setValue(OrderConstants.SHIPPING_FEE, "0");
        }
    }

    /**
     * 订单类型校验
     */
    private void validateOrderType(OrderCreateRequest request) {
        // 活动订单校验
        if (request.getOrderType() != OrderType.NORMAL.getCode()) {
            // 检查活动订单只能包含一个商品
            if (request.getItems().size() != 1) {
                logger.warn("活动订单只能包含一个商品: orderType={}, itemSize={}",
                        request.getOrderType(), request.getItems().size());
                throw new BusinessException(ErrorCode.ORDER_ITEM_PARAM_ERROR.getCode(), "活动商品一次只能购买一种SKU");
            }
        }
        if (request.getPromotionId() != null) {
            Promotion promotion = promotionMapper.selectByPrimaryKey(request.getPromotionId());
            if (promotion == null || !Objects.equals(promotion.getType(), OrderType.coverToPromotionType(request.getOrderType()))) {
                logger.warn("订单类型与活动类型不批拍");
                throw new BusinessException(ErrorCode.ORDER_TYPE_ERROR);
            }
        }

    }

    /**
     * 计算商品总金额
     */
    protected BigDecimal calculateItemTotalAmount(OrderItemRequest item) {
        return item.getUnitPrice()
                .multiply(new BigDecimal(item.getQuantity()))
                .setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * 计算订单总金额
     */
    protected BigDecimal calculateTotalAmount(List<OrderItemRequest> items) {
        return items.stream()
                .map(item -> item.getUnitPrice()
                        .multiply(new BigDecimal(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * 添加订单超时任务
     *
     * @param orderId
     */
    private void addTimeoutTask(Long orderId, Date payExpireTime) {
        try {
            String cron = String.format(GeneralConstants.CRON_FORMAT, LocalDateTime.now().getSecond());
            ScheduledTask scheduledTask = new ScheduledTask();
            scheduledTask.setId(idGenerator.nextId());
            scheduledTask.setTaskType(TaskType.ORDER_TIMEOUT.name());
            scheduledTask.setBusinessId(orderId);
            scheduledTask.setExecuteTime(payExpireTime);
            scheduledTask.setStatus(GeneralConstants.BT0);
            scheduledTask.setMaxRunsCount(GeneralConstants.MAX_RETRY);
            scheduledTask.setCron(cron);
            scheduledTaskMapper.insert(scheduledTask);
            logger.info("已添加订单超时任务orderId={}", orderId);
        } catch (Exception e) {
            log.warn("添加订单超时任务失败，orderId={}", orderId, e);
        }
    }

    /**
     * 扣除用户积分&&添加用户积分变更记录
     *
     * @param points
     * @param userId
     * @param orderId
     */
    private void deductUserPointsAndAddIntegralRecord(int points, long userId, long orderId) {
        try {
            customerMapper.deductUserPoints(userId, points);
            logger.info("已扣除用户积分userId={}, points={}", userId, points);
            int currentPoints = customerMapper.selectPointsByUserId(userId);
            IntegralRecord record = new IntegralRecord();
            record.setId(idGenerator.nextId());
            record.setUserId(userId);
            record.setPoints(-points);
            record.setCurrentBalance(currentPoints);
            record.setType(IntegralType.ORDER_DEDUCTION.getCode());
            record.setBusinessType(IntegralType.BusinessType.order.name());
            record.setDescription(IntegralType.ORDER_DEDUCTION.getDesc());
            record.setBusinessId(String.valueOf(orderId));
            integralRecordMapper.insert(record);
            logger.info("已添加用户积分记录userId={}, recordId={}", userId, record.getId());
        } catch (Exception e) {
            logger.warn("扣除用户积分&&添加用户积分变更记录，失败");
        }
    }

    public Map<Long, ProductSpu> validateProductInfo(OrderItemRequest item) {
        // 一次性获取所有需要的ID
        List<Long> spuIds = Collections.singletonList(item.getSpuId());
        List<Long> skuIds = Collections.singletonList(item.getSkuId());

        // 验证商品信息
        Map<Long, ProductSpu> spuMap = batchGetAndValidateSpus(spuIds);
        Map<Long, ProductSku> skuMap = batchGetAndValidateSkus(skuIds, spuMap);
        ProductSku productSku = skuMap.get(item.getSkuId());
        item.setSkuOriginalPrice(productSku.getPrice());

        // 填充商品属性
        completeSku(item, spuMap, productSku);

        return spuMap;
    }

}
